package com.xinghou.platform.dao.main.aspect;

import com.xinghou.platform.dao.main.SubjectDAO;
import com.xinghou.platform.dao.main.common.DBSubjectLevelCached;
import com.xinghou.platform.model.main.Subject;
import com.xinghou.platform.model.main.SubjectBrowse;
import com.xinghou.platform.model.main.SubjectReply;
import com.xinghou.platform.model.main.SubjectReplyPraise;
import com.xinghou.platform.util.JsonUtil;
import com.xinghou.platform.util.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

/**
 * Created by qingshengzheng on 16/6/26.
 */
@Aspect
@Component
public class SubjectCacheAspect extends DBSubjectLevelCached {
    @Resource
    SubjectDAO subjectDAO;

    @Pointcut("execution(public * com.xinghou.platform.dao.main.SubjectDAO.getSubjects(..))")
    public void getSubjects() {
    }

    @Pointcut("execution(public * com.xinghou.platform.dao.main.SubjectDAO.updateSubject(..))")
    public void updateSubject() {
    }

    @Pointcut("execution(public * com.xinghou.platform.dao.main.SubjectDAO.getSubjectDetail(..))")
    public void getSubjectDetail() {
    }

    @Pointcut("execution(public * com.xinghou.platform.dao.main.SubjectDAO.getHotReplyIds(..))")
    public void getHotReplyIds() {
    }

    @Pointcut("execution(public * com.xinghou.platform.dao.main.SubjectDAO.getLastSubject(..))")
    public void getLastSubject() {
    }

    @Pointcut("execution(public * com.xinghou.platform.dao.main.SubjectDAO.getSubjectJoinNumber(..))")
    public void getSubjectJoinNumber() {
    }

    @Pointcut("execution(public * com.xinghou.platform.dao.main.SubjectDAO.getSubjectClickNumber(..))")
    public void getSubjectClickNumber() {
    }

    @Pointcut("execution(public * com.xinghou.platform.dao.main.SubjectDAO.getSubjectShareNumber(..))")
    public void getSubjectShareNumber() {
    }

    @Pointcut("execution(public * com.xinghou.platform.dao.main.SubjectDAO.getSubjectReplyPaiseCount(..))")
    public void getSubjectReplyPaiseCount() {
    }
    @Pointcut("execution(public * com.xinghou.platform.dao.main.SubjectDAO.addSubjectReplyPraise(..))")
    public void addSubjectReplyPraise() {
    }

    @Pointcut("execution(public * com.xinghou.platform.dao.main.SubjectDAO.pubSubject(..))")
    public void pubSubject() {
    }

    @Pointcut("execution(public * com.xinghou.platform.dao.main.SubjectDAO.delSubject(..))")
    public void delSubject() {
    }

    @Pointcut("execution(public * com.xinghou.platform.dao.main.SubjectDAO.subjectReply(..))")
    public void subjectReply() {
    }

    @Pointcut("execution(public * com.xinghou.platform.dao.main.SubjectDAO.delSubjectReply(..))")
    public void delSubjectReply() {
    }

    @Pointcut("execution(public * com.xinghou.platform.dao.main.SubjectDAO.getSubjectReplyById(..))")
    public void getSubjectReplyById() {
    }

    @Pointcut("execution(public * com.xinghou.platform.dao.main.SubjectDAO.getSubjectReplyNumber(..))")
    public void getSubjectReplyNumber() {
    }

    @Pointcut("execution(public * com.xinghou.platform.dao.main.SubjectDAO.likeReply(..))")
    public void likeReply() {
    }

    @Pointcut("execution(public * com.xinghou.platform.dao.main.SubjectDAO.isPraised(..))")
    public void isPraised() {
    }

    @Pointcut("execution(public * com.xinghou.platform.dao.main.SubjectDAO.updateSubjectShareCount(..))")
    public void updateSubjectShareCount() {
    }

    @Pointcut("execution(public * com.xinghou.platform.dao.main.SubjectDAO.updateSubjectClickCount(..))")
    public void updateSubjectClickCount() {
    }

    @Pointcut("execution(public * com.xinghou.platform.dao.main.SubjectDAO.updateSubjectReply(..))")
    public void updateSubjectReply() {
    }

    @Pointcut("execution(public * com.xinghou.platform.dao.main.SubjectDAO.addSubjectJoinNum(..))")
    public void addSubjectJoinNum() {
    }

    @Pointcut("execution(public * com.xinghou.platform.dao.main.SubjectDAO.updateRandomJoinnum(..))")
    public void updateRandomJoinnum() {
    }

    @Pointcut("execution(public * com.xinghou.platform.dao.main.SubjectDAO.insertSubjectStatistics(..))")
    public void insertSubjectStatistics() {
    }

    @Pointcut("execution(public * com.xinghou.platform.dao.main.SubjectDAO.editSubjectJoinNum(..))")
    public void editSubjectJoinNum() {
    }

    /*@Around("getSubjects()")
    public void getSubjects(ProceedingJoinPoint pjp) throws Throwable {

    }*/
    @Around("insertSubjectStatistics()")
    public void insertSubjectStatistics(ProceedingJoinPoint pjp) throws Throwable {
        pjp.proceed();
        Long subjectid = (Long) ((Object[]) pjp.getArgs())[0];
        String keyjoinnum = String.format(CACHE_SUBJECT_JOINNUM, subjectid);
        getRedisClient().del(keyjoinnum, CACHED_SUBJECT_DB_INDEX);
    }
    @Around("pubSubject()")
    public void pubSubject(ProceedingJoinPoint pjp) throws Throwable {
        pjp.proceed();
        Subject subject = (Subject) ((Object[]) pjp.getArgs())[0];
        String key = String.format(CACHE_SUBJECT_ID, subject.id);
        getRedisClient().set(key, JsonUtil.toJson(subject), CACHED_SUBJECT_DB_INDEX);
        getRedisClient().zadd(CACHE_LAST_SUBJECT_IDSET,subject.pubtime, subject.id + "", CACHED_SUBJECT_DB_INDEX);
    }


    @Around("updateSubject()")
    public void updateSubject(ProceedingJoinPoint pjp) throws Throwable {
        Subject subject = (Subject) ((Object[]) pjp.getArgs())[0];
        pjp.proceed();
        String key = String.format(CACHE_SUBJECT_ID, subject.id);
        getRedisClient().set(key, JsonUtil.toJson(subject), CACHED_SUBJECT_DB_INDEX);

    }

    @Around("getSubjectDetail()")
    public Subject getSubjectDetail(ProceedingJoinPoint pjp) throws Throwable {
        Long subjectid = (Long)((Object[]) pjp.getArgs())[0];


        String key = String.format(CACHE_SUBJECT_ID, subjectid);
        Object jsonToken = getRedisClient().get(key, CACHED_SUBJECT_DB_INDEX);
        Subject subject = null;
        if (jsonToken == null) {
             subject = (Subject) pjp.proceed();
            if (subject != null)
                getRedisClient().set(key, JsonUtil.toJson(subject), CACHED_SUBJECT_DB_INDEX);
            return subject;
        } else {
             subject = (Subject) JsonUtil.fromJson(jsonToken.toString(), Subject.class);

        }



        return subject;
    }

    @Around("addSubjectJoinNum()")
    public void addSubjectJoinNum(ProceedingJoinPoint pjp) throws Throwable {
        Long subjectid = (Long)((Object[]) pjp.getArgs())[0];
        Long uid = (Long)((Object[]) pjp.getArgs())[1];
        String joinkey =  String.format(CACHE_SUBJECT_JOINNUM, subjectid);
        SubjectBrowse subjectBrowse = new SubjectBrowse();
        subjectBrowse.setCreatetime(System.currentTimeMillis());
        subjectBrowse.setSubjectid(subjectid);
        subjectBrowse.setUid(uid.intValue());
        subjectDAO.addSubjectBrowse(subjectBrowse);
        subjectDAO.updateSubjectJoinCount(String.valueOf(subjectid));
        subjectDAO.updateSubjectJoinRealCount(String.valueOf(subjectid));
        getRedisClient().incr(joinkey,CACHED_SUBJECT_DB_INDEX);
    }



    @Around("delSubject()")
    public void delSubject(ProceedingJoinPoint pjp) throws Throwable {
        Long subjectid = (Long)((Object[]) pjp.getArgs())[0];
        String key = String.format(CACHE_SUBJECT_ID, subjectid);
        getRedisClient().del(key,CACHED_SUBJECT_DB_INDEX);
        getRedisClient().zrem(CACHE_LAST_SUBJECT_IDSET,subjectid+"",CACHED_SUBJECT_DB_INDEX);

        pjp.proceed();
    }

    @Around("subjectReply()")
    public void subjectReply(ProceedingJoinPoint pjp) throws Throwable {
        pjp.proceed();
        SubjectReply reply = (SubjectReply) ((Object[]) pjp.getArgs())[0];
        String key = String.format(CACHE_SUBJECT_REPLYID, reply.id);
        getRedisClient().set(key, JsonUtil.toJson(reply), CACHED_SUBJECT_DB_INDEX);
        Long subjectid = reply.getSubjectid();
        subjectDAO.addSubjectReplyCount(String.valueOf(subjectid));
        String replycountkey =  String.format(CACHE_SUBJECT_REPLYNUM, String.valueOf(subjectid));
        getRedisClient().incr(replycountkey,CACHED_SUBJECT_DB_INDEX);
    }
    @Around("delSubjectReply()")
    public void delSubjectReply(ProceedingJoinPoint pjp) throws Throwable {
        Long replyid = (Long)((Object[]) pjp.getArgs())[0];
        Long subjectid = (Long)((Object[]) pjp.getArgs())[1];
        String key = String.format(CACHE_SUBJECT_REPLYID, replyid);
        getRedisClient().del(key,CACHED_SUBJECT_DB_INDEX);
        String setkey = String.format(CACHE_SUBJECT_REPLYID, subjectid);
        getRedisClient().zrem(setkey,replyid.toString(),CACHED_SUBJECT_DB_INDEX);
        String replycountkey =  String.format(CACHE_SUBJECT_REPLYNUM, subjectid);
        getRedisClient().decr(replycountkey, CACHED_SUBJECT_DB_INDEX);
        subjectDAO.remSubjectReplyCount(String.valueOf(subjectid));
        pjp.proceed();

    }

    @Around("likeReply()")
    public void likeReply(ProceedingJoinPoint pjp) throws Throwable {

        SubjectReplyPraise praise = (SubjectReplyPraise) ((Object[]) pjp.getArgs())[0];
        SubjectReply reply = subjectDAO.getSubjectReplyById(Long.parseLong(praise.replyid));
        if(null!=reply&&reply.replyTime!=null&&reply.replyTime<=System.currentTimeMillis()){
            String setkey = String.format(CACHE_HOT_REPLY_SET, praise.getSubjectid());
            getRedisClient().zincrby(setkey, 1, praise.replyid + "", CACHED_SUBJECT_DB_INDEX);
        }
        String praisekey = String.format(CACHE_SUBJECT_REPLY_PRAISE, praise.getReplyid());
        getRedisClient().incr(praisekey,CACHED_SUBJECT_DB_INDEX);
        String userlikekey =  String.format(CACHE_REPLY_USER_LIKE,praise.getReplyid(),praise.getUid());
        getRedisClient().set(userlikekey,"1",CACHED_SUBJECT_DB_INDEX);
        pjp.proceed();
    }

    @Around("updateSubjectReply()")
    public void updateSubjectReply(ProceedingJoinPoint pjp) throws Throwable {

        SubjectReply subjectReply = (SubjectReply) ((Object[]) pjp.getArgs())[0];
        SubjectReply reply = subjectDAO.getSubjectReplyById(subjectReply.id);
        if(null!=reply&&reply.replyTime!=null&&reply.replyTime<=System.currentTimeMillis()){
            String setkey = String.format(CACHE_HOT_REPLY_SET, subjectReply.getSubjectid());
            getRedisClient().zadd(setkey, subjectReply.getPraise_count(), subjectReply.id + "", CACHED_SUBJECT_DB_INDEX);
        }

        String praisekey = String.format(CACHE_SUBJECT_REPLY_PRAISE, subjectReply.id);

        getRedisClient().set(praisekey, subjectReply.getPraise_count()+"",CACHED_SUBJECT_DB_INDEX);
        String key = String.format(CACHE_SUBJECT_REPLYID, subjectReply.getId());
        getRedisClient().del(key,CACHED_SUBJECT_DB_INDEX);
        pjp.proceed();
    }


    @Around("isPraised()")
    public boolean isPraised(ProceedingJoinPoint pjp) throws Throwable {

        String replyid = (String) ((Object[]) pjp.getArgs())[0];

        String uid = (String) ((Object[]) pjp.getArgs())[1];

        if(StringUtils.isEmpty(uid)){
            return false;
        }

        String key =  String.format(CACHE_REPLY_USER_LIKE,replyid,uid);
        if(getRedisClient().exists(key,CACHED_SUBJECT_DB_INDEX)) {
            String praised = getRedisClient().get(key, CACHED_SUBJECT_DB_INDEX);
            if ("1".equals(praised)) {
                return true;
            } else if ("0".equals(praised)) {
                return false;
            }
        }
        int count = subjectDAO.praisedCount(replyid,uid);

        if(count==0){
            getRedisClient().set(key,"0",CACHED_SUBJECT_DB_INDEX);
            return false;
        }else{
            getRedisClient().set(key,"1",CACHED_SUBJECT_DB_INDEX);
            return true;
        }
    }


    @Around("getHotReplyIds()")
    public List<String> getHotReplyIds(ProceedingJoinPoint pjp) throws Throwable {
        Long subjectid = (Long)((Object[]) pjp.getArgs())[0];
        Integer count  = (Integer)((Object[]) pjp.getArgs())[1];
        if(count==null||count ==0){
            count = 5;
        }
        String key = String.format(CACHE_HOT_REPLY_SET, subjectid);
        Set<String> sets = getRedisClient().zrevrange(key, 0, count - 1, CACHED_SUBJECT_DB_INDEX);
        List<String> hotids = new ArrayList<String>();
        if (sets == null || sets.isEmpty()) {
            hotids = (List<String>) pjp.proceed();
            for (int i = 0; i < hotids.size(); i++) {
                String replyid = hotids.get(i);
                Long paiseCount = subjectDAO.getSubjectReplyPaiseCount(Long.parseLong(replyid));
                getRedisClient().zadd(key, paiseCount, hotids.get(i).toString(), CACHED_SUBJECT_DB_INDEX);
            }
            getRedisClient().expire(key,60*60,CACHED_SUBJECT_DB_INDEX);
            return hotids;

        } else {
            long overtime = getRedisClient().ttl(key,CACHED_SUBJECT_DB_INDEX);
            if(overtime<0) {
                getRedisClient().expire(key,60*60,CACHED_SUBJECT_DB_INDEX);
            }
            Iterator iterator = sets.iterator();
            while (iterator.hasNext()) {
                hotids.add((String) iterator.next());
            }

        }

        return hotids;
    }

    @Around("getSubjectReplyById()")
    public SubjectReply getSubjectReplyById(ProceedingJoinPoint pjp) throws Throwable {
        Long replyid = (Long)((Object[]) pjp.getArgs())[0];
        String key = String.format(CACHE_SUBJECT_REPLYID, replyid);
        Object jsonToken = getRedisClient().get(key, CACHED_SUBJECT_DB_INDEX);
        if (jsonToken == null) {
            SubjectReply reply = (SubjectReply) pjp.proceed();
            if (reply != null)
                getRedisClient().set(key, JsonUtil.toJson(reply), CACHED_SUBJECT_DB_INDEX);
            return reply;
        } else {
            SubjectReply reply = (SubjectReply) JsonUtil.fromJson(jsonToken.toString(), SubjectReply.class);
            return reply;
        }
    }


    @Around("getSubjectReplyPaiseCount()")
    public Long getSubjectReplyPaiseCount(ProceedingJoinPoint pjp) throws Throwable {
        Long replyid = (Long) ((Object[]) pjp.getArgs())[0];
        String key = String.format(CACHE_SUBJECT_REPLY_PRAISE, replyid);
        String temp = getRedisClient().get(key, CACHED_SUBJECT_DB_INDEX);
        if (StringUtils.isEmpty(temp)) {
            Long count = (Long) pjp.proceed();
            getRedisClient().set(key, count.toString(), CACHED_SUBJECT_DB_INDEX);
            return count;
        } else {
            Long count = Long.parseLong(temp);
            return count;

        }
    }

    @Around("addSubjectReplyPraise()")
    public void addSubjectReplyPraise(ProceedingJoinPoint pjp) throws Throwable {
        Long replyid = (Long) ((Object[]) pjp.getArgs())[0];
        String key = String.format(CACHE_SUBJECT_REPLY_PRAISE, replyid);
        String temp = getRedisClient().get(key, CACHED_SUBJECT_DB_INDEX);
        if (StringUtils.isEmpty(temp)) {
            Long count = subjectDAO.getSubjectReplyPaiseCount(Long.parseLong(temp));
            getRedisClient().set(key,(++count).toString(),CACHED_SUBJECT_DB_INDEX);

        } else {
            getRedisClient().incr(key,CACHED_SUBJECT_DB_INDEX);


        }
    }





    @Around("getLastSubject()")
    public Subject getLastSubject(ProceedingJoinPoint pjp) throws Throwable {
        Long timestamp = (Long) ((Object[]) pjp.getArgs())[0];
        Set<String> sets = getRedisClient().zrevrangeByScore(CACHE_LAST_SUBJECT_IDSET, timestamp, 0, 0, 1, CACHED_SUBJECT_DB_INDEX);
        if (sets == null || sets.isEmpty()) {
            Subject subject = (Subject) pjp.proceed();
            if(null == subject) {
                return null;
            }
            String key = String.format(CACHE_SUBJECT_ID, subject.id);
            getRedisClient().set(key, JsonUtil.toJson(subject), CACHED_SUBJECT_DB_INDEX);
            getRedisClient().zadd(CACHE_LAST_SUBJECT_IDSET,subject.createtime, subject.id + "", CACHED_SUBJECT_DB_INDEX);
            return subject;
        } else {
            String id = sets.iterator().next();
            Subject subject = subjectDAO.getSubjectDetail(Long.parseLong(id));
            return subject;
        }

    }

    @Around("getSubjectJoinNumber()")
     public String getSubjectJoinNumber(ProceedingJoinPoint pjp) throws Throwable {

        Long subjectid = (Long)  ((Object[]) pjp.getArgs())[0];
        String keyInfoId = String.format(CACHE_SUBJECT_JOINNUM, subjectid);
        String num = "0";
        if (getRedisClient().exists(keyInfoId, CACHED_SUBJECT_DB_INDEX)) {
            String temp = getRedisClient().get(keyInfoId, CACHED_SUBJECT_DB_INDEX);
            num = temp;
        } else {

            num =String.valueOf(pjp.proceed());
            getRedisClient().set(keyInfoId, num + "", CACHED_SUBJECT_DB_INDEX);
        }

        return num;
    }

    @Around("getSubjectClickNumber()")
    public String getSubjectClickNumber(ProceedingJoinPoint pjp) throws Throwable {

        Long subjectid = (Long)  ((Object[]) pjp.getArgs())[0];
        String keyInfoId = String.format(CACHE_SUBJECT_CLICKNUM, subjectid);
        String num = "0";
        if (getRedisClient().exists(keyInfoId, CACHED_SUBJECT_DB_INDEX)) {
            String temp = getRedisClient().get(keyInfoId, CACHED_SUBJECT_DB_INDEX);
            num = temp;


        } else {
            num =String.valueOf(pjp.proceed());
            getRedisClient().set(keyInfoId, num + "", CACHED_SUBJECT_DB_INDEX);
        }

        return num;
    }

    @Around("getSubjectShareNumber()")
    public String getSubjectShareNumber(ProceedingJoinPoint pjp) throws Throwable {

        Long subjectid = (Long)  ((Object[]) pjp.getArgs())[0];
        String keyInfoId = String.format(CACHE_SUBJECT_SHARENUM, subjectid);
        String num = "0";
        if (getRedisClient().exists(keyInfoId, CACHED_SUBJECT_DB_INDEX)) {
            String temp = getRedisClient().get(keyInfoId, CACHED_SUBJECT_DB_INDEX);
            num = temp;
        } else {
            num =String.valueOf(pjp.proceed());
            getRedisClient().set(keyInfoId, num + "", CACHED_SUBJECT_DB_INDEX);
        }

        return num;
    }

    @Around("getSubjectReplyNumber()")
    public String getSubjectReplyNumber(ProceedingJoinPoint pjp) throws Throwable {

        Long subjectid = (Long)  ((Object[]) pjp.getArgs())[0];
        String keyInfoId = String.format(CACHE_SUBJECT_REPLYNUM, subjectid);
        String num = "0";
        if (getRedisClient().exists(keyInfoId, CACHED_SUBJECT_DB_INDEX)) {
            String temp = getRedisClient().get(keyInfoId, CACHED_SUBJECT_DB_INDEX);
            num = temp;
        } else {
            num =String.valueOf(pjp.proceed());
            getRedisClient().set(keyInfoId, num + "", CACHED_SUBJECT_DB_INDEX);
        }

        return num;
    }

    @Around("updateSubjectShareCount()")
    public void updateSubjectShareCount(ProceedingJoinPoint pjp) throws Throwable {
        pjp.proceed();
        String subjectid = (String)  ((Object[]) pjp.getArgs())[0];
        String sharekey = String.format(CACHE_SUBJECT_SHARENUM, subjectid);
        getRedisClient().incr(sharekey,CACHED_SUBJECT_DB_INDEX);

    }

    @Around("updateSubjectClickCount()")
    public void updateSubjectClickCount(ProceedingJoinPoint pjp) throws Throwable {
        pjp.proceed();
        String subjectid = (String)  ((Object[]) pjp.getArgs())[0];
        String clickkey = String.format(CACHE_SUBJECT_CLICKNUM, subjectid);
        getRedisClient().incr(clickkey,CACHED_SUBJECT_DB_INDEX);
    }

    @Around("updateRandomJoinnum()")
    public void updateRandomJoinnum(ProceedingJoinPoint pjp) throws Throwable {
        Long subjectid = (Long)  ((Object[]) pjp.getArgs())[0];
        Integer joinnum = (Integer)  ((Object[]) pjp.getArgs())[1];
        String joinnumkey = String.format(CACHE_SUBJECT_JOINNUM, subjectid);
        pjp.proceed();
        getRedisClient().incr(joinnumkey,joinnum,CACHED_SUBJECT_DB_INDEX);
    }


    @Around("editSubjectJoinNum()")
    public void editSubjectJoinNum(ProceedingJoinPoint pjp) throws Throwable {
        Long subjectid = (Long)  ((Object[]) pjp.getArgs())[0];
        Integer joinnum = (Integer)  ((Object[]) pjp.getArgs())[1];
        String keyInfoId = String.format(CACHE_SUBJECT_JOINNUM, subjectid);
        pjp.proceed();
        getRedisClient().set(keyInfoId, joinnum + "", CACHED_SUBJECT_DB_INDEX);
    }
}
